/*
 *  Copyright 2008-2010 the original author or authors.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package org.openaecfm.spf.io;


import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;

import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openaecfm.spf.model.FileDescription;
import org.openaecfm.spf.model.FileName;
import org.openaecfm.spf.model.FileSchema;

/**
 * @author Qiu Kuining
 **/
public class DefaultExportSessionImpl implements IExportSession {

    private IAppDataManager appDataManager;
    private FileDescription fileDescription;
    private FileName fileName;
    private FileSchema fileSchema;
    private IEntityInstanceOutputFactory factory;
    public IEntityInstanceOutputFactory getFactory() {
		return factory;
	}

	public void setFactory(IEntityInstanceOutputFactory factory) {
		this.factory = factory;
	}

	public IEntityInstanceOutputFactoryUtil getFactoryUtil() {
		return factoryUtil;
	}

	public void setFactoryUtil(IEntityInstanceOutputFactoryUtil factoryUtil) {
		this.factoryUtil = factoryUtil;
	}

	private IEntityInstanceOutputFactoryUtil factoryUtil;
    private Writer writer;
    protected final Log logger = LogFactory.getLog(getClass());

    public DefaultExportSessionImpl(OutputStream os) {
        try {
            this.writer = this.makeWriter(os);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void setFileDescription(FileDescription fileDescription) {
        this.fileDescription = fileDescription;
    }

    @Override
    public void setFileName(FileName fileName) {
        this.fileName = fileName;
    }

    @Override
    public void setFileSchema(FileSchema fileSchema) {
        this.fileSchema = fileSchema;
    }

    @Override
    public void begin() {
        factory = getFactoryUtil().createFactory(fileSchema.getSchemaName() + ".xml");
        write("ISO-10303-21;\n");
        write("HEADER;\n");

        // write file description
        write(new FileDescriptionIO().exportSPF(fileDescription).toString());

        // Set file name
        write(new FileNameIO().exportSPF(fileName).toString());

        // Set file schema
        write(new FileSchemaIO().exportSPF(fileSchema).toString());

        write("ENDSEC;\n");

        write("DATA;\n");
    }

    @Override
    public void close() {
        write("ENDSEC;\n");
        write("END-ISO-10303-21;\n");
        flush();
    }

    private void flush() {
        try {
            writer.flush();
        } catch (IOException ex) {
            Logger.getLogger(DefaultExportSessionImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Get an OutputStreamWriter, using prefered encoding
     * (see {@link Format#setEncoding}).
     */
    private Writer makeWriter(OutputStream out)
            throws java.io.UnsupportedEncodingException {

        Writer w = new BufferedWriter(
                (new OutputStreamWriter(
                new BufferedOutputStream(out), "ISO-8859-1")));
        return w;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public void write(Object pojo) {
        IEntityInstanceOutput output = getFactory().createEntityInstanceOutput(pojo.getClass());
        write(output.exportSPF(pojo, appDataManager));
    }

    public void write(String str) {
        try {
            writer.write(str);
        } catch (IOException ex) {
            Logger.getLogger(DefaultExportSessionImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void setAppDataManager(IAppDataManager appDataManager) {
        this.appDataManager = appDataManager;
    }
}
